perm filename FORK.LSP[LIB,LSP] blob sn#290542 filedate 1977-06-27 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00007 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002	 MACLSP FORK PACKAGE
C00007 00003	(defun writefork (filnam fork# expr)
C00015 00004	(LAP FORKME SUBR)
C00019 00005	(ENTRY MSG SUBR)
C00022 00006	(ENTRY GMSG SUBR)
C00028 00007	(ENTRY GETMYJOB SUBR)
C00029 ENDMK
C⊗;
;;; MACLSP FORK PACKAGE
;;; Written by Jorge Phillips (6/22/77 last modification)

(declare (*lexpr  fork sndmsg)) 
(declare (setsyntax 54 500500 54))

(defun createfork (dmpfil uplowfile)
;;; dmpfil is the dumpfile to be run as a separate process. It is a 4 list
;;; uplowfile is a 2-list that specifies communication file TO lower fork in the
;;; CRUNIT directory of the luser. returns a dotted pair (lowerfork# . comfile)
;;; where comfile is the lower-upper communication file
;;; startup protocol
;;;	fork 		------>  starts
;;;     snd job#	------>  wait for job#
;;;	wait OK		<------  send OK
;;;     snd file	------>  wait for file
;;;	wait file	<------  send file
;;;		HANDSHAKE COMPLETE
(prog (lowfrk#)
      (and (not (equal (length dmpfil) 4))
	   (print '(need complete dmp pathname))
	   (break createfork t))
      (setq lowfrk# (fork (car dmpfil)(cadr dmpfil)(caddr dmpfil)(cadddr dmpfil)))
      (or lowfrk# (break '|Bletch!!! No fork created.| T))
      (return (synchfork lowfrk# uplowfile))))
      
(defun synchfork (fork# file)
;;; sets up synch protocol with startfork. returns dotted pair as in createfork
;     (sendjob fork#)
      (waitmsg 'OK fork#)
      (sndfilmsg fork# file (getmyjob))
      (cons fork# (getfilmsg (car fork#))))

(defun fork l	
;;; fork is a lexpr that takes 4 atomic args, fil ext p pn, that should
;;; specify a dmp file to be run as a separate fork. It returns the job number
;;; of the created fork as a fixnum. Notice that fork receives dmp file in 6bit
;;; returns (createdfork# . ourjob#)
(prog (crppn fil ext p pn)
      (and (or (> l 4) (< l 1)) 
	   (print '(Too many or few args in FORK))(break fork t))
      (setq crppn (crunit))
      (and (< l 4) (setq pn (car (pnget (cadadr crppn) 6)))	;sixbit pn
	   (go a))
      (setq pn (car (pnget (arg 4) 6)))
a     (and (< l 3) (setq p (car (pnget (caadr crppn) 6)))	;sixbit p
	   (go a1))
      (setq p (car (pnget (arg 3) 6)))
a1    (and (< l 2) (setq ext (car (pnget 'dmp 6)))			;def. ext = DMP
	   (go a2))
      (setq ext (car (pnget (arg 2) 6)))
a2    (setq fil (car (pnget (arg 1) 6)))
      (return (forkme fil ext (mergeppn p pn)))))

(defun startfork (lowupfil)
;;; lowupfil is a 2-list representing the file that will be used for 
;;; communication from the lower to the upper fork. returns the a dotted
;;; pair of the form (upperfork# . filnam)
;;; the first thing a child fork should do is call this routine
(prog (upfork# uplofil)
      (uclose)
      (gc)(setq ↑T t)
      (setq upfork# (fork-suspend))		;gets job # of parent fork
      (sndmsg upfork# 'OK (getmyjob))		;synch
      (setq uplofil (getfilmsg upfork#))	;get up-low file name
      (sndfilmsg upfork# lowupfil (getmyjob))		;file message
      (return (cons upfork# uplofil))))

(defun getjob nil
;;; getjob waits for a message of type JOB from anybody. Presumably this is
;;; the parent of this fork. Notice that waitmsg returns (JOB job#)
     (cadr (waitmsg 'JOB nil)))


(defun sendjob (fork#)
;;; sends job# of this fork to fork fork#
     (sndmsg fork# 'JOB (getmyjob)))
(defun writefork (filnam fork# expr)
;;; writes on file FILNAM s-expr EXPR and notifies fork FORK#
;;; should not be used for value
    (uwrite)          				;open file for writing
    (ioc r)(ioc w)
    (print expr)
    (ioc v)					;restore printout to tty
    (apply 'ufile (list (car filnam) 
		        (or (cadr filnam) 'FRK)))	;close it
    (sndmsg fork# 'READ (getmyjob))	 		;notify fork to read
)

(defun readfork (filnam fork#)
;;; reads an s-expr from the file filnam (a communication file), waiting
;;; for a notification from fork# to go ahead
   (waitmsg 'READ fork#)		       ;wait till read message comes
   (apply 'uread filnam)		       ;start reading from file
   (ioc q)				       ;start
   (prog2 nil (read) (uclose)))		       ;get s-expr

(defun checkfork (filnam fork#)
;;; checks for an s-expr from the file filnam (a communication file), if there is
;;; a notification from fork# it returns the expression, else nil
   (cond ((chkmsg 'READ fork#)		       ;wait till read message comes
   	  (apply 'uread filnam)		       ;start reading from file
   	  (ioc q)			       ;start
       	  (prog2 nil (read) (uclose)))))       ;get s-expr

;;;
;;; the following are interface routines with lap code
;;;

(defun sndfilmsg (forknum file from)
;;; send intercommunication file name to fork forknum. file should be a 2-list
;;; of form (filnam ext) in the crunit directory.
;;; from is job# of this job. should have been acquired by mail or by forking
   (or (fixp from) (error '|Foo luser!! Bad fork: | from))
   (and (not (equal (length file) 2))
	(print '(need full pathname!))
	(break sndfilmsg t))
   (sndmsg  forknum 'FIL from file))

(defun sndmsg mess
;;; lexpr that assembles message in mail buffer and ships it out to fork
;;; must have at least 3 args, the first one an integer (forknum), the
;;; second one a message type. The third one is the caller's job#. The 
;;; fourht one is a list of atoms (of less  than 5 chars each, restriction to dissapear)
;;; which is converted into a list of ascii fixnum equivalents and assembled
;;; consecutively as the message. system limits the size of this list to
;;; at most 30 words (the first two words carry msgtyp and jobnum). Notice that
;;; only the first 5 chars are used of each pname. Returns NIL if
;;; the message could not be sent due to full mailbox, NOJOB if the fork doesnt
;;; exist and T otherwise
   (and (or (< mess 3)(> mess 4))
	(princ '|Wrong # args!|)
	(break sndmsg t))
  (do nil
   ((msg (arg 1)
	(and (arg 2)(car (pnget (arg 2) 7)))	;nil if no type
	(and (= mess 4)(mapcar (function (lambda (w)(car (pnget w 7))))
			       (arg 4)))
	(arg 3) ) )))

(defun waitmsg (type fork#)
(prog (w)
   a	(setq w (chkmsg type fork#)) ;wait and check incoming mail
	(and w (return w))	     ;chkmsg returned message
	(go a)))

(defun getfilmsg (forknum)
;;; waits for file message to come from fork
     (cddr (waitmsg 'FIL forknum)))  ;return the file message i.e cddr

(defun chkmsg (type fork#)
;;; checks if an incoming message is of the adequate type and comes from
;;; the adequate sender.If so returns a list of the form
;;;		<type job# ! message>
(prog (w)
      a	(setq w (gmsg))		;get a message
	(and  (or (and type (eq type (car w))) T)
	      (or (and fork# (= fork# (cadr w))) T)
	      (return w))    ;message is the right one
	(return nil)))

(defun gimme (l num)
;;; l is a list of atoms in ascii. num is transformed into an interned atom and
;;; nconced at the end of the list. Num is a fixnum equiv. to 5 ascii chars
((lambda (w) (or (and l (nconc l w)) w))
 (list (pnput (list num) t))))
(LAP FORKME SUBR)
(ARGS FORKME (NIL . 3))
;;; this routine creates a new process with name provided in the
;;; form (FOO BAR (BLE TCH)) which should be a dump file to
;;; be started. Usually this sysout should execute a STARTFORK, which when
;;; released will give it the job number of its creator (like a fork handle)
;;; the file name should be preprocessed and translated into 3 args in sixbit
;;; as follows: A = filnam B= ext C=prjprg. Just sprouts the new process
;;; and returns T if successful and NIL if not (ie busy). ALL the args must appear.
;;; The calling routine should provide the corresponding defaults. Device is
;;; always DSK
	(JSP T FXNV1)			;first arg should be integer
	(MOVEM TT (+ FILE 1))		;move filnam (returned in TT
	(JSP T FXNV2)			;so should extension. result in D
					;ext comes in upper part of D
	(ADDI D 4)			;mode bit to start as phantom
	(MOVEM D (+ FILE 2))		;ext + modes
	(JSP T FXNV3)			;ppn in SIXBIT integer?
	(MOVEM R (+ FILE 4))		;ppn to SWAP arg list
	(MOVE TT (% 0 0 FILE))		;[0,,FILE]
	(CALLI TT 400004)		;swap creating process; returns fork# in TT
	(JUMPE TT FOO)			;failure? if so return NIL
	(JRST 0 FIX1)			;job number of new process. FXCONS and POPJ
FOO	(HLLZI A)			;return NIL (error)
	(POPJ P)
FILE	(SIXBIT DSK)
	(BLOCK 5)			;swap file info
FORK 	(BLOCK 1)
(ENTRY MSG SUBR)
(ARGS MSG (NIL . 4))
;;; in A receives fixnum for fork#. In B receives fixnum for operation. This fixnum
;;; is chopped in the lower half (i.e only 3 first chars are considered. Lower
;;; half will hold current job#. The third arg if non-nil will point to a list
;;; of fixnums to assemble as the message. The 4th arg is the originating job#
	(JSP T FXNV1)			;A to number. TT holds fork num in 0,,777777
	(MOVEM TT MSG)			;fork#
	(MOVSI TT -32)			;clear mailbox
	(SETZM 0 LETTER(TT))
	(AOBJN TT,(- * 1))
;;	at this point C holds the list and AR1 the jobnum as a fix#
	(JSP T FXNV2)			;B to number. D holds operation
	(MOVEM D LETTER)		;header is TYPE and JOB#
	(MOVE AR1 0 AR1)		;get job# from fixnum cons cell
	(MOVEM AR1 (+ LETTER 1))	;here is job
	(MOVSI TT -30)			;at most 30 words to transfer
	(MOVE A C)			;save pointer to list. C has pointer
TST	(JUMPE A DONE)			;either done transferring or no message
	(HLRZ C 0 A)			;car
	(JSP T FXNV3)			;check its fixnum
	(MOVEM R (+ LETTER 2)(TT))	;move ascii to message
	(HRRZ A 0 A)			;A← cdr(A)
	(AOBJN TT,TST)
DONE	(MAIL 5 MSG)   			;skpsend
	(JRST 0 BOXFUL)			;mailbox busy
	(JRST 0 OK)	
	(MOVEI A (QUOTE NOJOB))		;no such fork
	(POPJ P)
BOXFUL  (HLLZI A)			;return NIL
	(POPJ P)
OK	(MOVEI A (QUOTE T))		;return T
	(POPJ P)
MSG	(BLOCK 1)			;MSG=fork# MSG+1 points to message
	(0 0 LETTER)
LETTER  (BLOCK 32)
(ENTRY GMSG SUBR)
(ARGS GMSG (NIL . 0))
;;; This function waits for a message from any fork. Message format is
;;;
;;;		-----------------
;;;	MESS    TYPE ascii 1 word
;;;		-----------------
;;;     MESS+1  JOB integer			;originating job#
;;;		-----------------
;;;	MESS+2       ......			;start of message as asciz words
;;;		-----------------
;;; 		     ......
;;;		-----------------
;;;     MESS+30      ......
;;;		-----------------
;;;
;;; It convets the type into an interned atom, converts the job# to fixnum,
;;; generates a list of the message atoms and returns
;;;		<type job# ! message>
    	(MAIL 1 BUFFER)		;WRCV. Wait till message is received
	(MOVE TT BUFFER)	;get message type
	(JSP T FXCONS)		;convert to FIXNUM for GIMME
	(MOVE B A)		;now we do <type>
	(HLLZI A)		;A ← NIL
	(CALL 2 (FUNCTION GIMME)) ; returns <type>
	(PUSH FXP A)		;save result
	(MOVE TT (+ BUFFER 1))	;get job#
	(JSP T FXCONS)		;convert to fixnum
	(HLLZI B)
	(CALL 2 (FUNCTION CONS)) ;returns <job#>
	(MOVE B A)
	(POP FXP A)		;now append to get in A <type job#>
	(CALL 2 (FUNCTION APPEND))

;;;
;;; Now we construct the message if any, and nconc it to the list. Message
;;; starts at BUFFER+2. A holds <type job#>
;;;
     	(MOVSI AR1 -30)		;up to 30 word messages
REPEAT 	(MOVE B (+ BUFFER 2)(AR1)) ;get current element
	(JUMPE B LUSER)		;if zeros then done
	(MOVE TT B)		;get fixnum
	(PUSH FXP A)		;A will be clobbered
	(JSP T FXCONS)		;return FIXNUM
	(MOVE B A)		;B holds fixnum 
	(POP FXP A)		;well, A holds list again
	(PUSH FXP AR1)		;save AR1 (ie count)
	(CALL 2 (FUNCTION GIMME)) ;returns in A append1(A (pnput ..B.. T))
	(POP FXP AR1)
	(AOBJN AR1 REPEAT)	;repeat
LUSER  	(POPJ P)		;return
BUFFER  (BLOCK 32)		;message fooey! kludge so losing lap works

(ENTRY MERGEPPN SUBR)
(ARGS MERGEPPN (NIL . 2))
;;; places p in left and pn in right half
	(MOVE TT 0 A)			;get prj sixbit into TT
	(JSP T NORMAL)			;right justify within halfword
	(PUSH FXP TT)			;save in stack
	(MOVE TT 0 B)			;get pn sixbit
	(JSP T NORMAL)			;same
	(HLRZ TT TT)			;TT has 0,,pn
	(HLL TT 0 FXP)			;TT now has p,,pn
	(MOVE A TT)			;return p,,pn
	(JSP T FXCONS)			;get fixnum
	(POP FXP FXP)
	(POPJ P)
NORMAL	(MOVSI D -3)			;at most 3 sixbit chars
        (TLNE TT 000077)		;last 6 bits are zero?
	(JRST 0 ALL)			;OK tested
	(LSH TT -6)			;shift right 6 bits
	(AOBJN D (- * 3))
ALL	(JRST 0 @ T)			;return
(ENTRY GETMYJOB SUBR)
(ARGS GETMYJOB (NIL . 0))	
;;; returns fixnum with job# of caller. used to pass handles to forks
	(MOVEI TT 226)
	(CALLI TT 33)
	(CALLI TT 33)
	(JRST 0 FIX1)

(ENTRY FORK-SUSPEND SUBR)
(ARGS FORK-SUSPEND (NIL . 0))
	(MOVEM 17 (+ ACS 17))	;Save the accs
	(MOVEI 17 ACS)
	(BLT 17 (+ ACS 16))
;should insert here code to print out suspend message
	(MOVEI TT STRT)
	(MOVEM TT 120)
	(CALLI 1 12)		;Exit 1,
STRT	(MOVEM TT JOB)		;Save master job number
	(HRLZI 17 ACS)		;restore acs
	(BLT 17 17)
	(MOVE TT JOB)
	(JRST 0 FIX1)		;Number cons job number
JOB	(0)
ACS	(BLOCK 20)
NIL